All files / web/src/app/practice/[studentId]/dashboard page.tsx

0% Statements 0/110
0% Branches 0/1
0% Functions 0/1
0% Lines 0/110

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111                                                                                                                                                                                                                             
import { notFound } from 'next/navigation'
import { canPerformAction } from '@/lib/classroom/access-control'
import {
  getAllSkillMastery,
  getPlayerCurriculum,
  getPracticeStudent,
  getRecentSessions,
  getRecentSessionResults,
} from '@/lib/curriculum/server'
import { getSessionMode } from '@/lib/curriculum/session-mode'
import { getSessionModeComfortLevel } from '@/lib/curriculum/session-mode-comfort'
import { getActiveSessionPlan } from '@/lib/curriculum/session-planner'
import { getUserId } from '@/lib/viewer'
import { DashboardClient } from './DashboardClient'

// Disable caching for this page - progress data should be fresh
export const dynamic = 'force-dynamic'

interface DashboardPageProps {
  params: Promise<{ studentId: string }>
  searchParams: Promise<{ tab?: string }>
}

/**
 * Dashboard Page - Server Component
 *
 * Shows the student's tabbed dashboard with:
 * - Overview tab: Current level, progress, session controls
 * - Skills tab: Detailed skill mastery, BKT analysis, skill management
 * - History tab: Past sessions (future)
 *
 * This page is always accessible regardless of session state.
 * Parents/teachers can view stats even while a session is in progress.
 *
 * URL: /practice/[studentId]/dashboard?tab=overview|skills|history
 */
export default async function DashboardPage({ params, searchParams }: DashboardPageProps) {
  const { studentId } = await params
  const { tab } = await searchParams

  // Get database user ID for authorization and socket notifications
  const userId = await getUserId()

  // Fetch player data in parallel (includes session mode to avoid client-side waterfall)
  const [player, curriculum, skills, recentSessions, activeSession, problemHistory, sessionMode] =
    await Promise.all([
      getPracticeStudent(studentId),
      getPlayerCurriculum(studentId),
      getAllSkillMastery(studentId),
      getRecentSessions(studentId, 200),
      getActiveSessionPlan(studentId),
      getRecentSessionResults(studentId, 2000), // For Skills tab BKT analysis
      getSessionMode(studentId),
    ])

  // 404 if player doesn't exist
  if (!player) {
    notFound()
  }

  // Check authorization - user must have view access to this player
  const hasAccess = await canPerformAction(userId, studentId, 'view')
  if (!hasAccess) {
    notFound() // Return 404 to avoid leaking existence of player
  }

  // Get skill IDs that are in the student's active practice rotation
  // practiceLevel !== 'none' means the skill is enabled for practice, NOT that it's mastered
  const currentPracticingSkillIds = skills.filter((s) => s.isPracticing).map((s) => s.skillId)

  // Compute comfort level (depends on sessionMode, so must be after Promise.all)
  const comfortResult = await getSessionModeComfortLevel(studentId, sessionMode)

  return (
    <DashboardClient
      studentId={studentId}
      player={player}
      curriculum={curriculum}
      skills={skills}
      recentSessions={recentSessions}
      activeSession={activeSession}
      currentPracticingSkillIds={currentPracticingSkillIds}
      problemHistory={problemHistory}
      initialTab={
        tab === 'overview' ||
        tab === 'skills' ||
        tab === 'history' ||
        tab === 'scoreboard' ||
        tab === 'notes' ||
        tab === 'observers' ||
        tab === 'relationships'
          ? (tab as
              | 'overview'
              | 'skills'
              | 'history'
              | 'scoreboard'
              | 'notes'
              | 'observers'
              | 'relationships')
          : undefined
      }
      userId={userId}
      initialSessionMode={{
        sessionMode,
        comfortLevel: comfortResult.overall,
        comfortByMode: comfortResult.byMode,
      }}
    />
  )
}